package cn.yunyichina.provider.pay.service.impl;

import cn.yunyichina.provider.iface.entity.cache.RedisKeyEnum;
import cn.yunyichina.provider.iface.entity.pay.PayCode;
import cn.yunyichina.provider.pay.dao.PaymentSettingAppRelationDao;
import cn.yunyichina.provider.pay.dao.PaymentSettingDao;
import cn.yunyichina.provider.pay.dao.SettlementSettingDao;
import cn.yunyichina.provider.pay.entity.PaymentSetting;
import cn.yunyichina.provider.pay.entity.PaymentSettingAppRelation;
import cn.yunyichina.provider.pay.entity.SettlementSetting;
import cn.yunyichina.provider.pay.exception.PaySettingNotFoundException;
import com.alibaba.dubbo.common.utils.CollectionUtils;
import com.alibaba.fastjson.JSON;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.List;

/**
 * Created by Lullaby on 2017/10/17
 */
@Service
public class RedisCacheServiceImpl {

    private final RedisTemplate<String, String> redisTemplate;

    private final SettlementSettingDao settlementSettingDao;

    private final PaymentSettingAppRelationDao paymentSettingAppRelationDao;

    private final PaymentSettingDao paymentSettingDao;

    @Autowired
    public RedisCacheServiceImpl(SettlementSettingDao settlementSettingDao,
                                 RedisTemplate<String, String> redisTemplate,
                                 PaymentSettingAppRelationDao paymentSettingAppRelationDao,
                                 PaymentSettingDao paymentSettingDao) {
        this.redisTemplate = redisTemplate;
        this.settlementSettingDao = settlementSettingDao;
        this.paymentSettingAppRelationDao = paymentSettingAppRelationDao;
        this.paymentSettingDao = paymentSettingDao;
    }

    public SettlementSetting getSettlementSetting(String appCode, String orgCode, int payMode) throws PaySettingNotFoundException {
        String field = appCode.concat("-").concat(orgCode).concat("-").concat(String.valueOf(payMode));

        HashOperations<String, String, String> hashOperations = redisTemplate.opsForHash();
        String result = hashOperations.get(RedisKeyEnum.PAY_SETTLEMENT_SETTING_CODE.getKey(), field);
        if (StringUtils.isEmpty(result)) {
            SettlementSetting settlementSetting = getSettlementSettingFromDatabase(appCode, orgCode, payMode);
            hashOperations.put(RedisKeyEnum.PAY_SETTLEMENT_SETTING_CODE.getKey(), field, JSON.toJSONString(settlementSetting));

            return settlementSetting;
        }

        return JSON.parseObject(result, SettlementSetting.class);
    }

    private SettlementSetting getSettlementSettingFromDatabase(String appCode, String orgCode, int payMode) throws PaySettingNotFoundException {
        SettlementSetting settlementSettingWheres = new SettlementSetting();
        settlementSettingWheres.setPlatformOrgAppCode(appCode);
        settlementSettingWheres.setDevOrgCode(orgCode);
        settlementSettingWheres.setPayMode((short) payMode);

        List<SettlementSetting> settlementSettings = settlementSettingDao.select(settlementSettingWheres);
        if (CollectionUtils.isEmpty(settlementSettings)) {
            throw new PaySettingNotFoundException("no record in pay_settlement_setting under conditions app_code:" + appCode + ", org_code:" + orgCode + ", pay_mode:" + payMode);
        }

        return settlementSettings.get(0);
    }

    public PaymentSettingAppRelation getPaymentSettingAppRelation(String appCode, String payOrgCode, int payMode) throws PaySettingNotFoundException {
        String field;
        if (StringUtils.isEmpty(payOrgCode)) {
            field = appCode.concat("-").concat(String.valueOf(payMode));
        } else {
            field = appCode.concat("-").concat(payOrgCode).concat("-").concat(String.valueOf(payMode));
        }

        HashOperations<String, String, String> hashOperations = redisTemplate.opsForHash();
        String result = hashOperations.get(RedisKeyEnum.PAY_PAYMENT_RELATION_CODE.getKey(), field);
        if (StringUtils.isEmpty(result)) {
            PaymentSettingAppRelation paymentSettingAppRelation = getPaymentSettingAppRelationFromDatabase(appCode, payOrgCode, payMode);
            hashOperations.put(RedisKeyEnum.PAY_PAYMENT_RELATION_CODE.getKey(), field, JSON.toJSONString(paymentSettingAppRelation));

            return paymentSettingAppRelation;
        }

        return JSON.parseObject(result, PaymentSettingAppRelation.class);
    }

    private PaymentSettingAppRelation getPaymentSettingAppRelationFromDatabase(String appCode, String payOrgCode, int payMode) throws PaySettingNotFoundException {
        PaymentSettingAppRelation psarWheres = new PaymentSettingAppRelation();
        psarWheres.setPlatformOrgAppCode(appCode);
        psarWheres.setOrgCode(payOrgCode);
        psarWheres.setPayMode((short) payMode);

        List<PaymentSettingAppRelation> paymentSettingAppRelations = paymentSettingAppRelationDao.select(psarWheres);
        if (CollectionUtils.isEmpty(paymentSettingAppRelations)) {
            throw new PaySettingNotFoundException("no record in pay_payment_setting_app_relation under conditions app_code:" + appCode + ", org_code:" + payOrgCode + ", pay_mode:" + payMode);
        }

        return paymentSettingAppRelations.get(0);
    }

    public PaymentSetting getPaymentSettingById(String id) throws PaySettingNotFoundException {
        HashOperations<String, String, String> hashOperations = redisTemplate.opsForHash();
        String result = hashOperations.get(RedisKeyEnum.PAY_PAYMENT_SETTING_ID.getKey(), id);
        if (StringUtils.isEmpty(result)) {
            PaymentSetting paymentSetting = getPaymentSettingByIdFromDatabase(id);
            hashOperations.put(RedisKeyEnum.PAY_PAYMENT_SETTING_ID.getKey(), id, JSON.toJSONString(paymentSetting));

            return paymentSetting;
        }

        return JSON.parseObject(result, PaymentSetting.class);
    }

    private PaymentSetting getPaymentSettingByIdFromDatabase(String id) throws PaySettingNotFoundException {
        PaymentSetting paymentSettingWheres = new PaymentSetting();
        paymentSettingWheres.setId(id);

        List<PaymentSetting> paymentSettings = paymentSettingDao.select(paymentSettingWheres);
        if (CollectionUtils.isEmpty(paymentSettings)) {
            throw new PaySettingNotFoundException("no record in pay_payment_setting under conditions id:" + id);
        }

        return paymentSettings.get(0);
    }

    public PaymentSetting getPaymentSettingByAppId(String appId) throws PaySettingNotFoundException {
        HashOperations<String, String, String> hashOperations = redisTemplate.opsForHash();
        String result = hashOperations.get(RedisKeyEnum.PAY_PAYMENT_SETTING_APPID.getKey(), appId);
        if (StringUtils.isEmpty(result)) {
            PaymentSetting paymentSetting = getPaymentSettingByAppIdFromDatabase(appId);
            hashOperations.put(RedisKeyEnum.PAY_PAYMENT_SETTING_APPID.getKey(), appId, JSON.toJSONString(paymentSetting));

            return paymentSetting;
        }

        return JSON.parseObject(result, PaymentSetting.class);
    }

    private PaymentSetting getPaymentSettingByAppIdFromDatabase(String appId) throws PaySettingNotFoundException {
        PaymentSetting paymentSettingWheres = new PaymentSetting();
        paymentSettingWheres.setPayAppId(appId);

        List<PaymentSetting> paymentSettings = paymentSettingDao.select(paymentSettingWheres);
        if (CollectionUtils.isEmpty(paymentSettings)) {
            throw new PaySettingNotFoundException("no record in pay_payment_setting under conditions app_id:" + appId);
        }

        return paymentSettings.get(0);
    }

    public boolean reloadPaymentSettingCache(String appCode, String orgCode, String payCode) {
        try {
            int payMode = PayCode.valueOf(payCode).getMode();
            HashOperations<String, String, String> hashOperations = redisTemplate.opsForHash();

            String field;
            if (!StringUtils.isEmpty(orgCode)) {
                field = appCode.concat("-").concat(orgCode).concat("-").concat(String.valueOf(payMode));
                SettlementSetting settlementSetting = getSettlementSettingFromDatabase(appCode, orgCode, payMode);
                hashOperations.put(RedisKeyEnum.PAY_SETTLEMENT_SETTING_CODE.getKey(), field, JSON.toJSONString(settlementSetting));

                if (orgCode.equals(settlementSetting.getPlatformCode())) {
                    orgCode = null;
                }
            }

            PaymentSettingAppRelation paymentSettingAppRelation = getPaymentSettingAppRelationFromDatabase(appCode, orgCode, payMode);
            if (StringUtils.isEmpty(orgCode)) {
                field = appCode.concat("-").concat(String.valueOf(payMode));
            } else {
                field = appCode.concat("-").concat(orgCode).concat("-").concat(String.valueOf(payMode));
            }
            hashOperations.put(RedisKeyEnum.PAY_PAYMENT_RELATION_CODE.getKey(), field, JSON.toJSONString(paymentSettingAppRelation));

            PaymentSetting paymentSetting = getPaymentSettingByIdFromDatabase(paymentSettingAppRelation.getPaymentSettingId());
            hashOperations.put(RedisKeyEnum.PAY_PAYMENT_SETTING_ID.getKey(), paymentSetting.getId(), JSON.toJSONString(paymentSetting));
            hashOperations.put(RedisKeyEnum.PAY_PAYMENT_SETTING_APPID.getKey(), paymentSetting.getPayAppId(), JSON.toJSONString(paymentSetting));

            return true;
        } catch (Exception e) {
            return false;
        }
    }

}
